//---------------------------------------------------------------------------


#pragma hdrstop

#include "TLine.h"
#include "TGraphForm.h"
#include "TMainForm.h"
#include <fastmath.h>
#include "Math.hpp"
//---------------------------------------------------------------------------

#pragma package(smart_init)
//-- constructor ------------------------------------------------------------
__fastcall TLine::TLine(TCanvas *_Canvas, TArea *_Area) :
   Canvas(_Canvas),
   Area(_Area),
   Orient(true),
   Visible(true),
   MarkDir(false),
   Weight(0)
{
  Pen = new TPen;
  Text = new TText;
  Pen->Width = 2;
}

//-- destructor ------------------------------------------------------------
__fastcall TLine::~TLine()
{
  delete Pen;
  delete Text;
}
//-- assigner ---------------------------------------------------------------
void __fastcall TLine::Assign(TLine * _Line, bool Points)
{
  Pen->Assign(_Line->Pen);
  if (Points) {
    BeginPM = _Line->BeginPM;
    EndPM = _Line->EndPM;
  }  
  Text->Assign(_Line->Text);

  Orient = _Line->Orient;
  Visible = _Line->Visible;
  MarkDir = _Line->MarkDir;

  WT = _Line->WT;

  Weight = _Line->Weight;

  x1 = _Line->x1;
  x2 = _Line->x2;
  y1 = _Line->y1;
  y2 = _Line->y2;
}
//---------------------------------------------------------------------------
void __fastcall TLine::ToFile(TMemo * Memo)
{
  Memo->Lines->Add("<Edge>");
  // bool
  Memo->Lines->Add(BoolToAS(Orient));
  Memo->Lines->Add(BoolToAS(Visible));
  Memo->Lines->Add(BoolToAS(MarkDir));
  // int
  Memo->Lines->Add(IntToStr(Weight));
  // double
  Memo->Lines->Add(FloatToStr(x1));
  Memo->Lines->Add(FloatToStr(x2));
  Memo->Lines->Add(FloatToStr(y1));
  Memo->Lines->Add(FloatToStr(y2));
  // Pen
  Memo->Lines->Add(IntToStr(Pen->Width));
  Memo->Lines->Add(IntToStr(int(Pen->Color)));
  Memo->Lines->Add(IntToStr(int(Pen->Style)));
  // other
  Memo->Lines->Add(IntToStr(int(WT)));
  // points
  Memo->Lines->Add(IntToStr(BeginPM->Index));
  Memo->Lines->Add(IntToStr(EndPM->Index));
  // dinamic structures
  Text->ToFile(Memo);
}
//---------------------------------------------------------------------------
void __fastcall TLine::FromFile(int &i, TMemo *Memo)
{
  i++;
  // bool
  Orient = ASToBool(Memo->Lines->Strings[i]); i++;
  Visible = ASToBool(Memo->Lines->Strings[i]); i++;
  MarkDir = ASToBool(Memo->Lines->Strings[i]); i++;
  // int
  Weight = StrToInt(Memo->Lines->Strings[i]); i++;
  // double
  x1 = StrToFloat(Memo->Lines->Strings[i]); i++;
  x2 = StrToFloat(Memo->Lines->Strings[i]); i++;
  y1 = StrToFloat(Memo->Lines->Strings[i]); i++;
  y2 = StrToFloat(Memo->Lines->Strings[i]); i++;
  // Pen
  Pen->Width = StrToInt(Memo->Lines->Strings[i]); i++;
  Pen->Color = TColor(StrToInt(Memo->Lines->Strings[i])); i++;
  Pen->Style = TPenStyle(StrToInt(Memo->Lines->Strings[i])); i++;
  // other
  WT  = TWeightType(StrToInt(Memo->Lines->Strings[i])); i++;
  // point
  BeginPM = GraphForm[MainForm->i]->PointM[StrToInt(Memo->Lines->Strings[i])]; i++;
  EndPM = GraphForm[MainForm->i]->PointM[StrToInt(Memo->Lines->Strings[i])]; i++;
  // dinamic structures
  Text->FromFile(i, Memo);
}

//---------------------------------------------------------------------------
void __fastcall TLine::Draw()
{
  if (Visible)
    DrawLine();
}

//---------------------------------------------------------------------------
void __fastcall TLine::DrawLine()
{
  Canvas->Pen->Assign(Pen);
  
  x1 = Area->HorPos(BeginPM->xv);
  x2 = Area->HorPos(EndPM->xv);
  y1 = Area->VerPos(BeginPM->yv);
  y2 = Area->VerPos(EndPM->yv);

    // top
  if (y1 < Area->Rc.Top) {
    if (y2 - y1 != 0)
      x1 = x1 + (Area->Rc.Top - y1)*(x2 - x1)/(y2 - y1);
    y1 = Area->Rc.Top;
  }
  if (y2 < Area->Rc.Top) {
    if (y1 - y2 != 0)
      x2 = x2 + (Area->Rc.Top - y2)*(x1 - x2)/(y1 - y2);
    y2 = Area->Rc.Top;
  }
    // bottom
  if (y1 > Area->Rc.Bottom) {
    if (y1 - y2 != 0)
      x1 = x1 + (Area->Rc.Bottom - y1)*(x1 - x2)/(y1 - y2);
    y1 = Area->Rc.Bottom;
  }
  if (y2 > Area->Rc.Bottom) {
    if (y2 - y1 != 0)
      x2 = x2 + (Area->Rc.Bottom - y2)*(x2 - x1)/(y2 - y1);
    y2 = Area->Rc.Bottom;
  }
    // left
  if (x1 < Area->Rc.Left) {
    if (x2 - x1 != 0)
      y1 = y1 + (Area->Rc.Left - x1)*(y2 - y1)/(x2 - x1);
    x1 = Area->Rc.Left;
  }
  if (x2 < Area->Rc.Left) {
    if (x1 - x2 != 0)
      y2 = y2 + (Area->Rc.Left - x2)*(y1 - y2)/(x1 - x2);
    x2 = Area->Rc.Left;
  }
    // right
  if (x1 > Area->Rc.Right) {
    if (x1 - x2 != 0)
      y1 = y1 + (Area->Rc.Right - x1)*(y1 - y2)/(x1 - x2);
    x1 = Area->Rc.Right;
  }
  if (x2 > Area->Rc.Right) {
    if (x2 - x1 != 0)
      y2 = y2 + (Area->Rc.Right - x2)*(y2 - y1)/(x2 - x1);
    x2 = Area->Rc.Right;
  }
  if (!((x1 == x2) && (y1 == y2))) {
    Canvas->MoveTo(x1, y1);
    Canvas->LineTo(x2, y2);
    if (MarkDir)
      DrawArrow();
  }    
}
//---------------------------------------------------------------------------
double __fastcall TLine::GetLength()
{
  double a = eabs(BeginPM->xv - EndPM->xv);
  double b = eabs(BeginPM->yv - EndPM->yv);
  return sqrt(sqr(a) + sqr(b));
}
//---------------------------------------------------------------------------
__fastcall TLine::DrawArrow()
{
  x1 = Area->HorPos(BeginPM->xv);
  x2 = Area->HorPos(EndPM->xv);
  y1 = Area->VerPos(BeginPM->yv);
  y2 = Area->VerPos(EndPM->yv);
  int cx = (x1 + x2)/2;
  int cy = (y1 + y2)/2;
  if ((cx > Area->Rc.Left) && (cx < Area->Rc.Right))
    if ((cy > Area->Rc.Top) && (cy < Area->Rc.Bottom)) {
      TPoint Pt[5];
      double angle;
      if ((x1 < x2) && (y1 > y2)) angle = _fm_atan((eabs(x1 - x2)/eabs(y1 - y2)));
      else
      if ((x1 > x2) && (y1 < y2)) angle = _fm_atan((eabs(x1 - x2)/eabs(y1 - y2))) + M_PI;
      else
      if ((x1 < x2) && (y1 < y2)) angle = _fm_atan((eabs(y1 - y2)/eabs(x1 - x2))) + M_PI/2;
      else
      if ((x1 > x2) && (y1 > y2)) angle = _fm_atan((eabs(y1 - y2)/eabs(x1 - x2))) - M_PI/2;
      else {
        if (x1 == x2) {
          if (y1 > y2) angle = 0;
          else angle = M_PI;
        }
        else
          if (y1 == y2) {
            if (x1 > x2) angle = -M_PI/2;
            else angle = M_PI/2;
          }
        }
      const l = 10;
      int w = Pen->Width/2;
      Canvas->Brush->Color = Pen->Color;
      Canvas->Brush->Style = bsSolid;
      Canvas->Pen->Width = 1;
      Pt[0].x = cx; Pt[0].y = cy;
      Pt[4].x = cx; Pt[4].y = cy;
      Pt[1].x = cx + (l/2 + w)*cos(angle);
      Pt[1].y = cy + (l/2 + w)*sin(angle);
      Pt[2].x = cx + (l + w*2)*cos(angle - M_PI/2);
      Pt[2].y = cy + (l + w*2)*sin(angle - M_PI/2);
      Pt[3].x = cx + (l/2 + w)*cos(angle + M_PI);
      Pt[3].y = cy + (l/2 + w)*sin(angle + M_PI);
      Canvas->Polygon(Pt, 4);
   }
}
